package main
import (
	"fmt" 
	"unsafe"
	"strconv"
)

func main () {
	fmt.Println("---1.1.整数数据类型-有符号-int---")

	var i int = 1
	fmt.Println("i=", i)

	// int8 的范围 -128 ~ 127
	var j int8 = 127
  // j = 128  
	// cannot use 128 (untyped int constant) as int8 value in variable declaration (overflows)
	fmt.Println("int8", "j=", j)

	fmt.Println("---1.2.整数数据类型-无符号-uint---")

	var i1 uint = 0
	// i1 = -1 
	// cannot use -1 (untyped int constant) as uint value in variable declaration (overflows)
	fmt.Println("i=", i1)

	// int8 的范围 -128 ~ 127
	var j1 uint8 = 255
  // j = 256
	// cannot use 256 (untyped int constant) as int8 value in variable declaration (overflows)
	fmt.Println("int8", "j=", j1)

	fmt.Println("---1.3.整型的类型---")
	// int , uint , rune , byte 的使用
	var a int = 8900
	fmt.Println("a=", a)
	var b uint = 1
	var c byte = 255
	fmt.Println(b, c)

	fmt.Println("---1.4.整型的使用细节-查看数据类型---")

	var n1 = 100 // ? n1 是什么类型
	// fmt.Printf() 可以用于做格式化输出
	fmt.Printf("n1 的类型是 %T \n", n1)

	fmt.Println("---1.5.整型的使用细节-查看变量占用字节大小和数据类型---")

	// 如何查看某个变量占用字节大小和数据类型 (使用将多) 
	var n2 int64 = 10
	fmt.Printf("n2 的类型 %T  n2 占用的字节数是 %d ", n2, unsafe.Sizeof(n2))

	fmt.Println("---2.1.小数类型---")

	var price float32 = 89.12
	fmt.Println("price=", price)
	
	fmt.Println("---2.2.浮点数在机器中存放形式---")
	var num1 float32 = -0.00089
	var num2 float64 = -7809656.09
	fmt.Println("num1=", num1, "num2=", num2)
	// num1= -0.00089 num2= -7.80965609e+06

	fmt.Println("---2.3.尾数部分可能丢失，造成精度损失---")
	var num3 float32 = -123.0000901
	var num4 float64 = -123.0000901
	fmt.Println("num3=", num3, "num4=", num4)
	// num3= -123.00009 num4= -123.0000901

	fmt.Println("---2.4.浮点型默认声明为float64 ---")
	var num5 = 1.1
	fmt.Printf("num5 的数据类型是 %T \n", num5)
	// num5 的数据类型是 float64
	
	fmt.Println("---2.5.十进制数形形式 ---")
	num6 := 5.12
	num7 := .123 // -> 0.123
	fmt.Println("num6=", num6, "num7=", num7)
	// num6= 5.12 num7= 0.123

	fmt.Println("---2.6.科学计数法形式 ---")
	num8 := 5.1234e2 // ? 5.1234 * 10的2次方
	num9 := 5.1234E2 // ? 5.1234 * 10的2次方
	num10 := 5.1234E-2 // ? 5.1234 / 10的2次方 
	fmt.Println("num8=", num8, "num9=", num9, "num10=", num10)
	// num8= 512.34 num9= 512.34 num10= 0.051234

	fmt.Println("---3.字符类型 ---")
	var c1 byte = 'a'
	var c2 byte = '0'

	// 当我们直接输出byte值，就是输出他的对应字符的码值
	fmt.Println("c1=", c1, "c2=", c2)
	// c1= 97 c2= 48

	// 如果我们希望输出对应字符，需要使用格式化输出
	fmt.Printf("c1=%c c2=%c \n", c1, c2)

	// var c3 byte = '鹏' 
	// fmt.Printf("c3=%c", c3)
	// cannot use '鹏' (untyped rune constant 40527) as byte value in variable declaration (overflows)

	var c3 int = '鹏'
	fmt.Printf("c3=%c c3对应码值=%d \n", c3, c3)

	// 可以直接给某个变量赋值一个数字，然后按格式化输出时 %c ，会输出该数字对应的 unicode
	var c4 int = 22269 // 22269 -> '国'
	fmt.Printf("c4=%c \n", c4)
	// c4=国

	// 字符类型是可以进行运算的， 相当于一个整数，运算时是按照码值运算
	var c5 = 10 + 'a' // a 的码值为 97  10 + 97 = 107
	fmt.Println("c5=", c5)
	// c5= 107

	fmt.Println("---4.布尔类型 ---")
	var bb = false 
	fmt.Println("bb=", bb)

	// bool 类型的占用存储空间是1个字节
	fmt.Println("bb 的占用空间：", unsafe.Sizeof(bb))
	// bb 的占用空间： 1

	// bool 类型只能取 true / false
	// bb = 1 
	// cannot use 1 (untyped int constant) as bool value in assignment

	fmt.Println("---5.字符串类型 ---")
	var address string = "北京长城 110 hello world!"
	fmt.Println("address=", address)

	// 字符串一旦赋值，字符串就不能修改了  Go 中的字符串是不可变的
	var str = "hello world!"
	// str[0] = "a"
	// cannot assign to str[0] (value of type byte)
	fmt.Println("str=", str)

	str2 := "abc\nabc"
	fmt.Println("str2=", str2)

	str3 := `
	package main
	import (
		"fmt" 
	)

	func main () {
		str2 := "abc\nabc"
		fmt.Println("str2=", str2)
	}
	`
	fmt.Println("str3=", str3)
	/* 
	str3=
        package main
        import (
                "fmt"
        )

        func main () {
                str2 := "abc\nabc"
                fmt.Println("str2=", str2)
        }
	*/

	// 字符串拼接方式
	var str4 = "hello " + "world"
	str4 += " haha!"
	fmt.Println("str4=", str4)
	// str4= hello world haha!

	// 当一个拼接的操作过长时，可以分行写，需要注意: + 保留在上一行
	var str5 = "hello " + "world" + 
	"hello " + "world" +
	"hello " + "world"
	fmt.Println("str5=", str5)
	// str5= hello worldhello worldhello world

	fmt.Println("---6.基本数据类型的默认值 ---")
	var A int // 0
	var B float32 // 0
	var C float64 // 0
	var isMarried bool // false
	var name string // ""

	// 这里的 %v 表示按照变量的值输出
	fmt.Printf("A=%d  B=%v  C=%v  isMarried=%v  name=%v", A, B, C, isMarried, name)
	// A=0  B=0  C=0  isMarried=false  name=
	
	fmt.Println("---7.基本数据类型的相互转换 ---")
	// 将 i => float
	var i100 int = 100
	var ni float32 = float32(i100)
	var ni2 int8 = int8(i100)
	var ni3 int64 = int64(i100) // 低精度 -> 高精度

	fmt.Printf("i100=%v ni=%v ni2=%v ni3=%v \n", i100, ni, ni2, ni3)
	// i100=100 ni=100 ni2=100 ni3=100

	// 在转换中，比如 int64 转 int8 【-128 ~ 127】，编译时不会报错
	// 只是换的结果是按溢出处理，和我们希望的结果不一样
	var number1 int64 = 999999
	var number2 int8 = int8(number1)
	fmt.Println("number2=", number2)
	// number2= 63

	fmt.Println("---8.1.基本数据类型转 string  ---")
	var num101 int = 99
	var num102 float64 = 23.456
	var b101 bool = true
	var myChar byte = 'h'
	var str101 string // 空的 string

	// 使用第一种方式来转换 fmt.Sprintf 方法

	str101 = fmt.Sprintf("%d", num101)
	fmt.Printf("str101 type %T str101=%q \n", str101, str101)
	// str101 type string str101="99"

	str101 = fmt.Sprintf("%f", num102)
	fmt.Printf("str101 type %T str101=%q  \n", str101, str101)
	// str101 type string str101="23.456000"

	str101 = fmt.Sprintf("%t", b101)
	fmt.Printf("str101 type %T str101=%q  \n", str101, str101)
	// str101 type string str101="true"

	str101 = fmt.Sprintf("%c", myChar)
	fmt.Printf("str101 type %T str101=%q  \n", str101, str101)
	// str101 type string str101="h"
	
	// 第二种方式 strconv 中的函数
	var num201 int = 99
	var num202 float64 = 23.456
	var b201  bool = true

	str101 = strconv.FormatInt(int64(num201), 10)
	fmt.Printf("str101 type %T str101=%q  \n", str101, str101)
	// str101 type string str101="99"

	str101 = strconv.FormatFloat(num202, 'f', 10, 64)
	// 说明： 'f'：格式   10：表示小数位保留10位  64：表示这个小数是 float64
	fmt.Printf("str101 type %T str101=%q  \n", str101, str101)
	// str101 type string str101="23.4560000000"

	str101 = strconv.FormatBool(b201)
	fmt.Printf("str101 type %T str101=%q  \n", str101, str101)
	// str101 type string str101="true"

	// strconv 包中有一个函数 Itoa
	var num203 int64 = 4567
	str101 = strconv.Itoa(int(num203))
	fmt.Printf("str101 type %T str101=%q  \n", str101, str101)
	// str101 type string str101="4567"

	fmt.Println("---8.2.string 类型转基本数据类型 ---")

	var str201 string = "true"
	var b301 bool

	b301 , _ = strconv.ParseBool(str201)
	/* 
	 * 说明
	 * 1. strconv.ParseBool() 函数会返回两个值 (value bool, err error)
	 * 2. 因为我只想获取到 value bool ，不想获取 err 所有我们用 _ 忽略掉
	*/
	fmt.Printf("b301 type %T b301=%v \n", b301, b301)
	// b301 type bool b301=true

	var str202 string = "123456"
	var n101 int64
	var n102 int
	n101, _ = strconv.ParseInt(str202, 10, 64)
	fmt.Printf("n101 type %T n101=%v \n", n101, n101)
	// n101 type int64 n101=123456
	n102 = int(n101)
	fmt.Printf("n102 type %T n102=%v \n", n102, n102)
	// n102 type int n102=123456
	
	var str203 string = "123.456"
	var f1 float64 
	f1, _ = strconv.ParseFloat(str203, 64)
	fmt.Printf("f1 type %T f1=%v \n", f1, f1)
	// f1 type float64 f1=123.456

	fmt.Println("---8.3.string 转基本数据类型的注意事项 ---")
	var str204 string = "hello"
	var n4 int64
	n4, _ = strconv.ParseInt(str204, 10, 64)
	fmt.Printf("n4 type %T n4=%v \n", n4, n4)
	// n4 type int64 n4=0

}